package de.wtschreiter.structured.document.io.event;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

import java.util.*;

import org.junit.Test;

public abstract class AbstractStartElementEventTest<START_ELEMENT_EVENT_TYPE extends StartElementEvent> {

    @Test
    public void testToString() {
        final String expectedToStringPattern = "StartElementEvent[namespace=%s,name=%s,attributes=%s]";
        final Map<String, String> attributes = setupSimpleAttributes();
        final String namespace = "a-namespace";
        final String name = "a-name";
        final StartElementEvent startElementEvent = newStartElementEvent(namespace, name, attributes);
        assertTrue(startElementEvent.toString().endsWith(
                String.format(expectedToStringPattern, namespace, name, attributes)));
    }

    @Test
    public void theSameObjectIsEquals() {
        final StartElementEvent startElementEvent = newStartElementEvent();
        assertTrue(startElementEvent.equals(startElementEvent));
    }

    @Test
    public void basicStartElementEventIsNotEqualsToNotStartElementEventObjects() {
        final StartElementEvent startElementEvent = newStartElementEvent();
        assertFalse(startElementEvent.equals("NotAStartElement"));
    }

    @Test
    public void basicStartElementEventIsEqualsToAnyStartElementEventWithSameSetOfAttributes() {
        final Map<String, String> attributes = setupSimpleAttributes();
        final String namespace = "a-namespace";
        final String name = "a-name";
        final StartElementEvent startElementEvent = newStartElementEvent(namespace, name, attributes);
        final StartElementEvent otherStartElementEvent = createMockStartElementEventWithAttributes(namespace, name,
                attributes);
        assertTrue(startElementEvent.equals(otherStartElementEvent));
    }

    private START_ELEMENT_EVENT_TYPE newStartElementEvent() {
        return newStartElementEvent(null, null, null);
    }

    protected abstract START_ELEMENT_EVENT_TYPE newStartElementEvent(final String namespace, final String name,
            final Map<String, String> attributes);

    private Map<String, String> setupSimpleAttributes() {
        final Map<String, String> attributes = new HashMap<>();
        attributes.put("key1", "value1");
        attributes.put("key2", "value2");
        attributes.put("key3", "value3");
        attributes.put("key4", "value4");
        return attributes;
    }

    private StartElementEvent createMockStartElementEventWithAttributes(final String namespace, final String name,
            final Map<String, String> attributes) {
        final StartElementEvent otherStartElementEvent = mock(StartElementEvent.class);
        when(otherStartElementEvent.getNamespace()).thenReturn(namespace);
        when(otherStartElementEvent.getName()).thenReturn(name);
        when(otherStartElementEvent.getAttributeKeys()).thenReturn(attributes.keySet());
        for (final String key : attributes.keySet()) {
            when(otherStartElementEvent.getAttribute(key)).thenReturn(attributes.get(key));
        }
        return otherStartElementEvent;
    }

}
